HashTable 与 HashMap 的区别

HashTable 与 HashMap 的区别

一、 HashTable 与 HashMap

1.1 HashTable 继承于 Dictionary 类

这里 table 里创建的是 Entry的接口
image

类中就是键值对和根据 hashcode 计算的 hash 值, 用于让 Entry 在 table 中分布得更加均匀, 减少 hash 冲突
image

1.2 两者区别

  • hashmap 大致等于 hashtable, 除了 hashtable 是线程安全的, 并且允许 null value 和 null key
    image

  • 两者都是Map接口的实现, 但是 hashmap 是继承与 AbstractMap 类


二、fail-fast 与 fail-safe

2.1 fail-fast 的解释

Dash查看文档 hashtable 文档中有一段话讲到

image

由这个类的所有“集合视图方法”返回的集合的迭代器方法返回的迭代器是fail fast的, 但是用 iterator 本身的方法则不会.

原因是 iterator 遍历集合的时候, 如果集合结构发生了变化(如: 删除一个 key - value) 则会抛出 ConcurrentModificationException, 但是修改则不会.

原因是其中有个变量 modCount 用以统计HashMap 结构改变的次数,

image

如果在遍历过程中有其他线程改变了 HashMap 的结构, 则造成 modCount 与 expectedModCount 不相等则抛出错误.
image

这里异常的抛出条件是检测到 modCount!= expectedmodCount 这个条件。如果集合发生变化时修改modCount值刚好又设置为了expectedmodCount值,则异常不会抛出。因此,不能依赖于这个异常是否抛出而进行并发操作的编程,这个异常只建议用于检测并发修改的bug。

image

2.2 安全失败(fail-safe)

采用安全失败机制的集合容器, 在遍历时不是直接在集合内容上访问的, 而是先复制原有集合内容, 在拷贝的集合上进行遍历.

原理: 由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发Concurrent Modification Exception.

缺点: 基于拷贝内容的优点是避免了 Concurrent Modification Exception, 但同样地, 迭代器并不能访问到修改后的内容,即: 迭代器遍历的是开始遍历那一刻拿到的集合拷贝, 在遍历期间原集合发生的修改迭代器是不知道的.

场景: java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用,并发修改。